home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d5 / maze21.arc / MAZE.C < prev    next >
Text File  |  1989-02-13  |  39KB  |  812 lines

  1. /*==========================================================================*/
  2. /*                        Maze generation program                           */
  3. /*                                                                          */
  4. /*                              Thomas G. Ore                               */
  5. /*                       3615 Fawn Cove Lane, Apt #6                        */
  6. /*                            Portage, MI 49002                             */
  7. /*                                                                          */
  8. /*                                   1988                                   */
  9. /*--------------------------------------------------------------------------*/
  10. /* This program was developed using Turboc-1.5 on an IBM PS/2 Model 50      */
  11. /*--------------------------------------------------------------------------*/
  12. /* This maze program will generate random mazes either smaller than the     */
  13. /* screen, the full size of the screen, larger than the screen or a user    */
  14. /* specified size.  The maze can be solved on screen or printed out.  The   */
  15. /* printer codes used are for an Epson printer, however codes for another   */
  16. /* type of printer can easily be added.  If the maze is solved on screen,   */
  17. /* the computer, the user, or both can be used to solve it.  While the      */
  18. /* computer is working on a solution, it picks random directions to search. */
  19. /* The only checks it does are not going down a known dead end path and not */
  20. /* going backwards unless it reaches a dead end.                            */
  21. /*==========================================================================*/
  22. /* Modifications by J. L.Wargula 07-06-88                                   */
  23. /*                  760 Pilgrim Trail                        */
  24. /*                  Sun Prairie, Wi  53590                    */
  25. /* using Turboc-1.5 on an CompuAdd Standard 286/10                          */
  26. /* Search comments for JLW to find modified sections.                       */
  27. /*==========================================================================*/
  28. #include "stdlib.h"
  29. #include "conio.h"
  30. #include "dos.h"
  31. #include "stdio.h"
  32. #include "time.h"
  33.  
  34. #define DEAD_END 177                        /* Char. signaling a dead end   */
  35. #define FACE 1                              /* The smiling face cursor      */
  36.  
  37. int  back(int);                             /* Ret. opp. direct. from input */
  38. void build_maze(void);                      /* Convert the tree to a maze   */
  39. void build_tree(void);                      /* Build the tree structure     */
  40. void deltas(int num,int *xstp,int *ystp);   /* Sets the move deltas         */
  41. void footer(int num);                       /* Prints the footer line       */
  42. void get_option(void);                      /* Get the maze size option     */
  43. void goto_xy(int x,int y);                  /* Move the cursor              */
  44. int  inkey(int *scan);                      /* Get a keystroke              */
  45. void init(void);                            /* Initialize the maze          */
  46. void refresh(void);                         /* Draws the maze to the screen */
  47. int  solve_maze(void);                      /* Solve the maze               */
  48. void solv_time(unsigned long int init_time);/* Calc's maze solve time       */
  49. void split_screen(void);                    /* Sets 43 or 50 line mode      */
  50. void trace_path(void);                      /* Trace the tree               */
  51. int  user_int(int num);                     /* User interface while solving */
  52. int  video_card(int *max_col,int *max_row); /* Goofy routine to get adapter */
  53.  
  54. /*............................ Global variables ............................*/
  55.  
  56. int *path,*trail,*maze;                     /* These are storage pointers   */
  57. int nrow,ncol;                              /* These are for *path & *trail */
  58. int num_row,num_col;                        /* These are for *maze          */
  59. int wall_col=2,path_col=3,solv_col=15;      /* Set the initial colors       */
  60. int curscol=15;                             /* The cursor color             */
  61. char solver='C';                            /* 'C' or 'M' for solve type    */
  62. char PRINTER;                               /* 'E'pson 'P'ro etc...    JLW  */
  63. int min_row,min_col;                        /* Maze uppr left display corner*/
  64. int max_row,max_col;                        /* Screen lowr rgt display limit*/
  65. int startup;                                /* For starting up              */
  66. int delr,delc;                              /* Centers the maze on screen   */
  67. FILE *outFile;                              /* For printing to printer      */
  68. int EGA=0, VGA=0, CGA=0;                    /* Adapter types  JLW           */
  69.  
  70. /*.............................. Main routine ..............................*/
  71.  
  72. void main(argc, argv)                       /* command-line opts by JLW     */
  73.   int argc;
  74.   char *argv[];
  75. {
  76.   unsigned long int init_time;              /* Maze solve time              */
  77.   int exit_key;                             /* The exit status flag         */
  78.   int card_type;                            /* The video mode (card)        */
  79.   char ch;
  80.  
  81.   ch=*argv[1];
  82.   if (argc>1) switch(ch) {                  /* command-line options by JLW  */
  83.     case 'H':                               /* help                         */
  84.     case 'h':                               /* help                         */
  85.     case '?':                               /* help                         */
  86.       printf("Usage is MAZE x <Enter>\n");
  87.       printf("    where x = E for wide carriage LQ Epson\n");
  88.       printf("              e for narrow carriage LQ Epson\n");
  89.       printf("              P for wide carriage Draft IBM Proprinter\n");
  90.       printf("              p for narrow carriage Draft IBM Proprinter (the default)\n");
  91.       return(0);                            /* out                          */
  92.     case 'E':
  93.     case 'e':
  94.     case 'P':
  95.       PRINTER=ch;
  96.       break;
  97.     case 'p':
  98.     default:
  99.       PRINTER='p';
  100.       break;
  101.     }
  102.     else PRINTER='p';
  103.   srand(time(0));                           /* Initialize the random # gen. */
  104.   total_restart:
  105.   startup=1;                                /* First time through           */
  106.   nrow=5; ncol=8;                           /* Use this for startup only    */
  107.  
  108.   card_type=video_card(&max_col,&max_row);  /* Get card type                */
  109.   if(card_type>18) VGA=1;                   /* record it  JLW               */
  110.   else if(card_type>15) EGA=1;              /*            JLW               */
  111.   else CGA=1;                               /*            JLW               */
  112.  
  113.   start_here:                               /* Go here to start after intro */
  114.   if(card_type!=0)textmode(3);              /* Set normal mode              */
  115.   else textmode(0);                         /* Use this if we have to       */
  116.  
  117.   if(max_row>25)split_screen();             /* Set to split screen mode     */
  118.  
  119.   if (max_col==80)
  120.   goto_xy((max_col-50)/2,1);                /* added JLW          */
  121.   else goto_xy(1,1);
  122.   printf("- Thomas G. Ore's SuperMaze 1988 Version 2.1 -");
  123.  
  124.   if(solver=='M') footer(1);                /* Print the footer line        */
  125.   else if(startup==0) footer(2);
  126.   else footer(3);
  127.  
  128.   resize_here:                              /* Go here to start new maze    */
  129.   num_col=2*ncol+3; num_row=2*nrow+3;       /* Set the maze dimensions      */
  130.  
  131. /*........................... Allocate the memory ..........................*/
  132. /*                                                                          */
  133. /* The entire maze is stored in dynamically allocated memory.  Two bytes    */
  134. /* are needed at each position to store the character and the color.  Thus  */
  135. /* the path, trail and maze are integer pointers.                           */
  136. /*                                                                          */
  137. /*..........................................................................*/
  138.  
  139.   path=(int *)calloc((nrow+1)*(ncol+1),sizeof(int));
  140.   trail=(int *)calloc((nrow+1)*(ncol+1),sizeof(int));
  141.   maze=(int *)calloc((num_row+1)*(num_col+1),sizeof(int));
  142.   if(path==NULL||trail==NULL||maze==NULL) { /* Check for NULL pointers      */
  143.     clrscr();                               /* Clear the screen             */
  144.     goto_xy((max_col-26)/2,(max_row-2)/2);  /* Write out a warning          */
  145.     printf("Failed to allocate memory.");
  146.     goto_xy((max_col-26)/2,(max_row-2)/2+1);
  147.     printf("Restart with smaller maze.");
  148.     getch();                                /* Wait for keyboard input      */
  149.     goto total_restart;                     /* Do a total restart           */
  150.   }
  151.  
  152. /*.........  Start through the routines and keep solving the maze ..........*/
  153.  
  154.   for(;;) {
  155.     init();                                 /* Initialize the arrays        */
  156.     build_tree();                           /* Build the tree               */
  157.     trace_path();                           /* Trace through the tree       */
  158.     build_maze();                           /* Build the maze               */
  159.     init_time=time(0);                      /* Store the starting time      */
  160.     exit_key=solve_maze();                  /* Solve the maze               */
  161.  
  162.     if(!exit_key&&!startup)solv_time(init_time); /* Print the solution time */
  163.     else if(exit_key==1||exit_key==2)       /* User said to exit            */
  164.      goto exit_here;
  165.     else if(exit_key==3) {                  /* Pick new maze size           */
  166.       startup=1;
  167.       goto exit_here;
  168.     }
  169.  
  170.     do {                                    /* Pick a new path color        */
  171.       path_col=rand()/4096+9;               /*                              */
  172.     } while(path_col>14);                   /* And don't go above 14        */
  173.     do {                                    /* Pick a new wall color        */
  174.       wall_col=rand()/4096+2;               /*                              */
  175.     } while(wall_col>7);                    /* And don't go above 7         */
  176.     if(solver=='C'&&startup==0) {           /* For computer solved          */
  177.       exit_key=2;
  178.       goto exit_here;
  179.     }
  180.   }                                         /* End of infinite loop         */
  181.  
  182. /*............... Exit here when through solving the maze ..................*/
  183.  
  184.   exit_here:
  185.   if(maze!=0)free(maze);                    /* Free the memory              */
  186.   if(trail!=0)free(trail);
  187.   if(path!=0)free(path);
  188.  
  189. /*......................... If we are not leaving ..........................*/
  190.  
  191.   if(exit_key!=1) {                         /* We are not quitting          */
  192.     get_option();                           /* Find out what to do next     */
  193.     if(startup==1) {                        /* Do this first time through   */
  194.       startup=0;
  195.       goto start_here;
  196.     }
  197.     else goto resize_here;
  198.   }
  199.   textmode(3);                              /* Set screen mode for exiting  */
  200. }                                           /* End of program               */
  201. /*--------------------------------------------------------------------------*/
  202. /*                         Initialize the variables                         */
  203. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  204. /* The maze is constructed by using three dynamically allocated arrays.  The*/
  205. /* path and trail contain the tree which defines the maze.  The path is the */
  206. /* forward direction and the trail is the backward direction.  The maze     */
  207. /* array is twice as large as the path and trail arrays because it must have*/
  208. /* room the the maze path and the walls in between.  The path and trail     */
  209. /* arrays are initialized to zero and the maze array is initialized to a    */
  210. /* checker board pattern with character 32 being the space and character 33 */
  211. /* being the wall.                                                          */
  212. /*--------------------------------------------------------------------------*/
  213. void init()
  214. {
  215.   register int i,j;
  216.  
  217.   min_row=min_col=1;                        /* Set the minimum row and col  */
  218.  
  219.   if(num_row-1<max_row)                     /* delr and delc center the maze*/
  220.    delr=(max_row-num_row+2)/2.;             /* if it is smaller than the    */
  221.   else delr=0;                              /* display screen               */
  222.   if(num_col-1<max_col)
  223.    delc=(max_col-num_col+2)/2.;
  224.   else delc=0;
  225.  
  226.   for(i=0;i<nrow;i++) {                     /* Clear path and trail arrays  */
  227.     for(j=0;j<ncol;j++)
  228.      *(path+i*ncol+j)=*(trail+i*ncol+j)=0;
  229.   }
  230.  
  231.   for(i=1;i<num_row;i++) {                  /* Set the maze array           */
  232.     for(j=1;j<num_col;j++)
  233.      *(maze+i*num_col+j)=33;
  234.     *(maze+i*num_col)=32;                   /* Blank out the outer edges    */
  235.     *(maze+(i+1)*num_col-1)=32;
  236.   }
  237.   for(j=0;j<=num_col;j++) {                 /* Blank out the top & bottom   */
  238.     *(maze+j)=32;
  239.     *(maze+(num_row-1)*num_col+j)=32;
  240.   }
  241.   for(i=2;i<num_row-1;i+=2) {               /* Blank out path               */
  242.     for(j=2;j<num_col-1;j+=2)
  243.      *(maze+i*num_col+j)=32;
  244.   }
  245. }
  246. /*--------------------------------------------------------------------------*/
  247. /*      The first step is to create a tree structure defining the path      */
  248. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  249. /* The tree structure ensures that the maze is completely filled and that   */
  250. /* there is alwalys one and only one solution through the maze.  The tree   */
  251. /* is started int the lower right corner and wanders aimlessly around.  The */
  252. /* path is not allowed to cross over itself, go outside the confines of the */
  253. /* rectangle or go backwards down it's own path.  When it reaches a dead    */
  254. /* end (no valid moves), it backtracks until a valid move is available.     */
  255. /* The tree is built by continuing to wander and backtrack until it returns */
  256. /* to the starting point.  When this occurs the maze is completely defined. */
  257. /*--------------------------------------------------------------------------*/
  258. void build_tree()
  259. {
  260.   int x,y,xstp,ystp;                        /* These define current position*/
  261.   int num,num_old=0;                        /* This is the move direction   */
  262.   int i,j;                                  /* These define new position    */
  263.   int bkwd=0;                               /* This is the backtracking flag*/
  264.   int ntry[5]={0,0,0,0,0};                  /* This tracks invalid moves    */
  265.  
  266.   x=nrow-1; y=ncol-1;                       /* Set the initial position     */
  267.  
  268.   for(;;) {                                 /* Enter an infinite loop       */
  269.     if(bkwd==0)*(trail+x*ncol+y)=num_old;   /* Keep track of our path       */
  270.     do {                                    /* Get number between 1 and 4   */
  271.       num=rand()/8192+1;
  272.     } while(num==num_old);                  /* Don't go backwards           */
  273.  
  274.     deltas(num,&xstp,&ystp);                /* Get the deltas               */
  275.     i=x+xstp; j=y+ystp;                     /* Set the new position         */
  276.  
  277. /*......... Don't move outside limits, or cross over our path ..............*/
  278.  
  279.     if(i<0||i>=nrow||j<0||j>=ncol||*(path+i*ncol+j)>0) {
  280.       ntry[num]=1;                          /* Keep track of bad direction  */
  281.       if((ntry[1]+ntry[2]+ntry[3]+ntry[4])==4) {/* We are at a dead end     */
  282.         for(i=1;i<=4;i++)ntry[i]=0;         /* Reset check                  */
  283.         if(bkwd==0)*(path+x*ncol+y)=5;      /* Set mark at dead end         */
  284.         bkwd=1;                             /* Set backtracking flag        */
  285.         num=*(trail+x*ncol+y);              /* This is backward direction   */
  286.         if(num==0)return;                   /* We are finished with the maze*/
  287.  
  288.         deltas(num,&xstp,&ystp);            /* Get the deltas               */
  289.         x+=xstp; y+=ystp;                   /* Set the new position         */
  290.  
  291.         num_old=back(num);                  /* Set the old direction        */
  292.         ntry[num_old]=1;                    /* Can't go back., so set flag  */
  293.       }
  294.     }
  295.  
  296. /*............................ Was a valid move ............................*/
  297.  
  298.     else {
  299.       *(path+x*ncol+y)=num;                 /* Set the path direction       */
  300.       bkwd=0;                               /* Reset the backtracking flag  */
  301.       num_old=back(num);                    /* num_old is opposite num      */
  302.       y=j; x=i;                             /* Set the new position         */
  303.       for(i=1;i<=4;i++)ntry[i]=0;           /* Reset check                  */
  304.       ntry[num_old]=1;                      /* Can't go back., so set flag  */
  305.     }
  306.   }
  307. }
  308. /*--------------------------------------------------------------------------*/
  309. /*         The second step is to trace path through the maze array          */
  310. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  311. /* The walls of the maze are constructed by tracing every dead end (a 5)    */
  312. /* all the wall to the begining of the maze (a 0).  The maze is formed by   */
  313. /* punching through the checker board pattern where there should be a path. */
  314. /*--------------------------------------------------------------------------*/
  315. void trace_path()
  316. {
  317.   register int i,j;
  318.   int x,y,xstp,ystp;
  319.  
  320.   for(i=0;i<nrow;i++) {                     /* Loop throuch the entire path */
  321.     for(j=0;j<ncol;j++) {                   /* and look for dead ends       */
  322.       if(*(path+i*ncol+j)==5) {             /* Found a dead end             */
  323.         x=i; y=j;                           /* Set the position             */
  324.         do {                                /* Trace backwards through loop */
  325.           deltas(*(trail+x*ncol+y),&xstp,&ystp); /* Get the deltas          */
  326.           *(trail+x*ncol+y)=0;              /* Set trail to zero            */
  327.           *(maze+(2*(x+1)+xstp)*num_col+2*(y+1)+ystp)=32;/* Set maze to zero*/
  328.           x+=xstp; y+=ystp;                 /* Set the position             */
  329.         } while(*(trail+x*ncol+y)>0);       /* Stop when no more trail      */
  330.       }
  331.     }
  332.   }
  333.   *(maze+1*num_col+2)=32;                   /* This is the start            */
  334.   *(maze+(num_row-2)*num_col+(num_col-3))=32; /* This is the end            */
  335. }
  336. /*--------------------------------------------------------------------------*/
  337. /*         The third step is to convert the maze to maze characters         */
  338. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  339. /* The maze is converted into a printable pattern by stopping at each wall  */
  340. /* character (>32) and checking the four adjacent wall characters.  The     */
  341. /* wall character being defined is determined by looking up the character in*/
  342. /* the walls array.                                                         */
  343. /*--------------------------------------------------------------------------*/
  344. void build_maze()
  345. {
  346.   register int i,j;
  347.   int walls[]={32,198,208,200,181,205,188,202,210,201,186,204,187,203,185,206};
  348.   int sum;
  349.  
  350.   for(i=1;i<num_row-1;i++) {                /* Go through entire array      */
  351.     for(j=1;j<num_col-1;j++) {
  352.       sum=0;
  353.       if(*(maze+i*num_col+j)>32) {          /* We are on a part of the wall */
  354.         if(*(maze+i*num_col+j+1)>32)sum+=1;
  355.         if(*(maze+(i-1)*num_col+j)>32)sum+=2;
  356.         if(*(maze+i*num_col+j-1)>32)sum+=4;
  357.         if(*(maze+(i+1)*num_col+j)>32)sum+=8;
  358.       }
  359.       *(maze+i*num_col+j)=walls[sum];       /* Set the wall character       */
  360.     }
  361.   }
  362.  
  363.   for(i=1;i<=num_row;i++)                   /* Go through entire array      */
  364.     for(j=1;j<=num_col;j++) *(maze+i*num_col+j)+=(wall_col<<8);
  365.  
  366.   for(i=0;i<=num_row;i++) *(maze+i*num_col)=DEAD_END+(solv_col<<8);
  367.   for(i=0;i<=num_row;i++) *(maze+(i+1)*num_col-1)=DEAD_END+(solv_col<<8);
  368.   for(i=0;i<=num_col;i++) *(maze+i)=DEAD_END+(solv_col<<8);
  369.   for(i=0;i<=num_col;i++) *(maze+num_row*num_col+i)=DEAD_END+(solv_col<<8);
  370. }
  371. /*--------------------------------------------------------------------------*/
  372. /*                   The final step is to solve the maze                    */
  373. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  374. /* The maze is solved by starting at the begining and randomly searching    */
  375. /* until it finds the exit.  The computer will search unless any key is     */
  376. /* hit.  When this happens, a menu is popped up to allow the user to make   */
  377. /* some choices.  While the computer is searching, it keeps track of dead   */
  378. /* ends and doesn't backtrack unless it reaches a dead end.                 */
  379. /*--------------------------------------------------------------------------*/
  380. int solve_maze()
  381. {
  382.   int far *ptr=(int far *) 0xB8000000;      /* For direct video writing     */
  383.   int x,y,xstp,ystp;
  384.   int i_was_here;
  385.   int num_old,num,sum=0;
  386.   int test_val,col;
  387.  
  388.   i_was_here=DEAD_END+(solv_col<<8);
  389.   x=1; y=2;                                 /* Start at upper left opening  */
  390.   num_old=0;                                /* Set the old direction        */
  391.   refresh();                                /* Draw the maze                */
  392.  
  393.   for(;;) {                                 /* Start an infinite loop       */
  394.  
  395.     if(kbhit()) {                           /* If any key hit               */
  396.       getch();                              /* Get the key with no echo     */
  397.       solver='M';                           /* Return to manual solve       */
  398.       if(startup!=1)footer(1);
  399.       else return(2);                       /* Jump out if this is startup  */
  400.     }
  401.  
  402.     *(maze+x*num_col+y)=FACE+(curscol<<8);  /* Place the cursor             */
  403.     *(ptr+(x-min_row+1+delr)*max_col+(y-min_col+delc))=FACE+(curscol<<8);
  404.  
  405.     do {
  406.       num=rand()/8192+1;                    /* Pick a random number (1 to 4)*/
  407.     } while(num==num_old);                  /* Don't go backwards           */
  408.  
  409.     if(solver=='M'&&(i_was_here&255)<=32&&(sum>2||(sum==2&&num_old==0))) {
  410.       num=user_int(num);
  411.       while(min_row>x)min_row--;            /* May have to reset screen     */
  412.       while(min_row+max_row-1<x)min_row++;
  413.       while(min_col>y)min_col--;
  414.       while(min_col+max_col-1<y)min_col++;
  415.       refresh();
  416.     }
  417.  
  418.     if(num==0)return(1);                    /* User said to exit            */
  419.     if(num==-1)return(3);                   /* User said to resize          */
  420.  
  421.     deltas(num,&xstp,&ystp);                /* Get the deltas               */
  422.     test_val=*(maze+(x+xstp)*num_col+(y+ystp));
  423.  
  424. /*. . . . . . . . . . . . . The new space is okay. . . . . . . . . . . . . .*/
  425.  
  426.     if((test_val&255)<=32) {
  427.       *(maze+x*num_col+y)=i_was_here;       /* Update the array             */
  428.       *(ptr+(x-min_row+1+delr)*max_col+(y-min_col+delc))=i_was_here;
  429.  
  430.       num_old=back(num);                    /* Keep track of our move       */
  431.       x+=xstp; y+=ystp;
  432.  
  433.       if(x==min_row&&min_row>0)min_row--;   /* Set the minimums             */
  434.       else if(x>min_row+max_row-2)min_row++;
  435.       else if(y==min_col&&min_col>0)min_col--;
  436.       else if(y>min_col+78)min_col++;
  437.       else goto jump;
  438.       refresh();                            /* Only refresh for min change  */
  439.  
  440.       jump:
  441.       sum=0;                                /* Find number of valid moves   */
  442.       if((*(maze+x*num_col+y+1)&255)<=32)sum+=1;
  443.       if((*(maze+(x-1)*num_col+y)&255)<=32)sum+=1;
  444.       if((*(maze+x*num_col+y-1)&255)<=32)sum+=1;
  445.       if((*(maze+(x+1)*num_col+y)&255)<=32)sum+=1;
  446.  
  447.       if(sum>1) {                           /* We have more than one choice */
  448.         if((i_was_here&255)==DEAD_END)num_old=0;
  449.         i_was_here=num+23+(path_col<<8);
  450.         if((*(maze+(x-xstp)*num_col+y-ystp)&255)!=DEAD_END) {
  451.           *(maze+(x-xstp)*num_col+y-ystp)=i_was_here;
  452.           *(ptr+(x-xstp-min_row+1+delr)*max_col+(y-ystp-min_col+delc))=
  453.            i_was_here;
  454.         }
  455.       }
  456.       else if(sum==1){                      /* There is just one move       */
  457.         if((*(maze+x*num_col+y+1)>>8)==solv_col)col=solv_col;
  458.         else if((*(maze+(x-1)*num_col+y)>>8)==solv_col)col=solv_col;
  459.         else if((*(maze+x*num_col+y-1)>>8)==solv_col)col=solv_col;
  460.         else if((*(maze+(x+1)*num_col+y)>>8)==solv_col)col=solv_col;
  461.         else col=path_col;
  462.         i_was_here=DEAD_END+(col<<8);
  463.         num_old=0;
  464.       }
  465.  
  466.       if(x==num_row-2&&y==num_col-3)return(0); /* FOUND OUR WAY OUT!!!      */
  467.     }                                       /* End of if-else               */
  468.   }                                         /* End of infinite loop         */
  469. }
  470. /*--------------------------------------------------------------------------*/
  471. /*              This routine puts the maze into screen memory               */
  472. /*--------------------------------------------------------------------------*/
  473. void refresh()
  474. {
  475.   int far *ptr=(int far *) 0xB8000000;
  476.   register int i,j,index,index1;
  477.   int row_end,col_end;
  478.  
  479.   if(num_row-1<max_row) row_end=num_row-2;
  480.   else row_end=max_row;
  481.   if(num_col-1<max_col) col_end=num_col-2;
  482.   else col_end=max_col;
  483.  
  484.   for(i=0;i<row_end;i++) {
  485.     index=(i+1+delr)*max_col+delc;
  486.     index1=(i+min_row)*num_col+min_col;
  487.     for(j=0;j<col_end;j++,index++,index1++)
  488.      *(ptr+index)=*(maze+index1);
  489.   }
  490. }
  491. /*--------------------------------------------------------------------------*/
  492. /*               This function returns the backward direction               */
  493. /*--------------------------------------------------------------------------*/
  494. int back(num)
  495. int num;
  496. {
  497.   if(num==1||num==3)return(num+1);
  498.   else return(num-1);
  499. }
  500. /*--------------------------------------------------------------------------*/
  501. /*                 This function returns the x and y deltas                 */
  502. /*--------------------------------------------------------------------------*/
  503. void deltas(num,xstp,ystp)
  504. int num;
  505. int *xstp,*ystp;
  506. {
  507.   switch (num) {                            /* Set deltas for direction num */
  508.     case 1: *xstp=-1; *ystp= 0; break;      /* Up                           */
  509.     case 2: *xstp= 1; *ystp= 0; break;      /* Down                         */
  510.     case 3: *xstp= 0; *ystp= 1; break;      /* Right                        */
  511.     case 4: *xstp= 0; *ystp=-1; break;      /* Left                         */
  512.   }
  513. }
  514. /*--------------------------------------------------------------------------*/
  515. /*            This routine does the user interface while solving            */
  516. /*--------------------------------------------------------------------------*/
  517. int user_int(int num)
  518. {
  519.   int keycode,scan;
  520.   int i,j,c;
  521.  
  522.   top:
  523.   keycode=inkey(&scan);                     /* Get the key with no echo     */
  524.   if(!keycode) switch (scan) {
  525.     case 75: num=4; break;                  /* left                         */
  526.     case 77: num=3; break;                  /* right                        */
  527.     case 72: num=1; break;                  /* up                           */
  528.     case 80: num=2; break;                  /* down                         */
  529.     case 59:                                /* F1 - Switch to computer solve*/
  530.       solver='C';
  531.       footer(2);
  532.       break;
  533.     case 60:                                /* F2 - Shift the screen        */
  534.       footer(4);
  535.       for(;;) {
  536.         keycode=inkey(&scan);
  537.         if(!keycode) switch (scan) {
  538.           case 75: if(min_col<num_col-2-max_col+1)min_col++; refresh(); break;
  539.           case 77: if(min_col>1)min_col--; refresh(); break;
  540.           case 72: if(min_row<num_row-2-max_row+1)min_row++; refresh(); break;
  541.           case 80: if(min_row>1)min_row--; refresh(); break;
  542.         }
  543.         else {
  544.           footer(1);
  545.           goto top;
  546.         }
  547.       }
  548.       case 61: return(-1);                  /* F3 - Exit to resize          */
  549.       case 62:                              /* F4 - Print the maze          */
  550.         outFile=fopen("PRN","wt");
  551.         biosprint(1, 0, 0);                 /* Initialize the printer  JLW  */
  552.  
  553.      if (PRINTER=='E')                      /* Epson wide carriage          */
  554.         {                                   /* original code for Epson      */
  555.         fprintf(outFile,"%c%c",27,64);      /* Initialize the printer       */
  556.         fprintf(outFile,"%c%c%c",27,120,1); /* Select LQ mode               */
  557.         fprintf(outFile,"%c%c%c",27,107,0); /* Select Typestyle             */
  558.         fprintf(outFile,"%c%c%c",27,116,1); /* Select graphics characters   */
  559.         if(num_col> 156)
  560.          fprintf(outFile,"%c%c",27,103);    /* Select 15 cpi                */
  561.         else if(num_col> 132)
  562.          fprintf(outFile,"%c%c",27,77);     /* Select 12 cpi                */
  563.         else if(num_col<= 132)
  564.          fprintf(outFile,"%c%c",27,80);     /* Select 10 cpi                */
  565.         else {
  566.           fclose(outFile);
  567.           break;
  568.           }
  569.         }
  570.      if (PRINTER=='e')                      /* Epson narrow carriage JLW    */
  571.         {                                   /* added code for Epson: JLW    */
  572.         fprintf(outFile,"%c%c",27,64);      /* Initialize the printer       */
  573.         fprintf(outFile,"%c%c%c",27,120,1); /* Select LQ mode               */
  574.         fprintf(outFile,"%c%c%c",27,107,0); /* Select Typestyle             */
  575.         fprintf(outFile,"%c%c%c",27,116,1); /* Select graphics characters   */
  576.         if(num_col> 96)
  577.          fprintf(outFile,"%c%c",27,103);    /* Select 15 cpi                */
  578.         else if(num_col> 80)
  579.          fprintf(outFile,"%c%c",27,77);     /* Select 12 cpi                */
  580.         else if(num_col<= 80)
  581.          fprintf(outFile,"%c%c",27,80);     /* Select 10 cpi                */
  582.         else {
  583.           fclose(outFile);
  584.           break;
  585.           }
  586.         }
  587.      if (PRINTER=='P')                      /* IBMproprinter wide carriage  */
  588.         {                                   /* added printer JLW  draft     */
  589.         if(num_col> 156)
  590.          fprintf(outFile,"%c",15);          /* Select 17 cpi                */
  591.         else if(num_col> 132)
  592.          fprintf(outFile,"%c%c",27,58);     /* Select 12 cpi                */
  593.         else if(num_col<= 132)
  594.          fprintf(outFile,"%c",18);          /* Select 10 cpi                */
  595.         else {
  596.           fclose(outFile);
  597.           break;
  598.           }
  599.         fprintf(outFile,"%c%c",27,48);      /* Select 8-lines/inch          */
  600.         }
  601.      if (PRINTER=='p')                      /* IBMproprinter narrow carriage*/
  602.         {                                   /* added printer JLW  draft     */
  603.         if(num_col> 96)
  604.          fprintf(outFile,"%c",15);      /* Select 17 cpi                */
  605.         else if(num_col> 80)
  606.          fprintf(outFile,"%c%c",27,58); /* Select 12 cpi                */
  607.         else if(num_col<= 80)
  608.          fprintf(outFile,"%c",18);      /* Select 10 cpi                */
  609.         else {
  610.           fclose(outFile);
  611.           break;
  612.           }
  613.         fprintf(outFile,"%c%c",27,48);      /* Select 8-lines/inch          */
  614.         }
  615.      for(i=0;i<num_row;i++) {               /* Print the maze               */
  616.           for(j=0;j<num_col;j++) {
  617.             c=(*(maze+i*num_col+j)&255);
  618.             if(c>32&&c!=DEAD_END) fprintf(outFile,"%c",c);
  619.             else fprintf(outFile,"%c",32);
  620.           }
  621.           fprintf(outFile,"\n");
  622.         }
  623.         fclose(outFile);
  624.         break;
  625.       case 63: return(0);                   /* Exit to quit to DOS          */
  626.   }
  627.   return(num);
  628. }
  629. /*--------------------------------------------------------------------------*/
  630. /*                This function prints the maze solve times                 */
  631. /*--------------------------------------------------------------------------*/
  632. void solv_time(unsigned long int init_time)
  633. {
  634.   int this_time;
  635.   static unsigned int min_time=999,max_time=0,avg_time=0,counter=0;
  636.  
  637.   this_time=(int)(time(0)-init_time);       /* Calculate the solve time     */
  638.  
  639.   if(this_time<min_time)min_time=this_time; /* Check the limits             */
  640.   if(this_time>max_time)max_time=this_time;
  641.   avg_time+=this_time;                      /* Calculate the avgerage time  */
  642.   counter+=1;
  643.   goto_xy(1,max_row+3);
  644.   printf("TIME%5d  AVG%5d  MIN%5d  MAX%5d", /* Print the times              */
  645.    this_time,avg_time/counter,min_time,max_time);
  646.   if(num_col>40)printf("  NUMBER%5d",counter);
  647. }
  648. /*--------------------------------------------------------------------------*/
  649. /*                     This function prints the footers                     */
  650. /*--------------------------------------------------------------------------*/
  651. void footer(int num)
  652. {
  653.   goto_xy(1,max_row+2);
  654.   switch (num) {
  655.     case 1:
  656.       cprintf("F1-Auto F2-Shift F3-New F4-Print F5-End");
  657.       break;
  658.     case 2:
  659.       cprintf("Hit any key to return to manual solve...");
  660.       break;
  661.     case 3:
  662.       goto_xy((max_col-23)/2,max_row+2);
  663.       cprintf("Hit any key to start...");
  664.       goto_xy((max_col-34)/2,max_row-1);               /* added JLW          */
  665.       cprintf("2.1 Version updates by J.L.Wargula");   /* added JLW          */
  666.       goto_xy((max_col-36)/2,max_row);                 /* added JLW          */
  667.       cprintf("Enter Maze H to list printer options"); /* added JLW          */
  668.       break;
  669.     case 4:
  670.       cprintf("Use arrows to shift, then hit space bar ");
  671.       break;
  672.   }
  673.   goto_xy(1,1);
  674. }
  675. /*--------------------------------------------------------------------------*/
  676. /*                 Set to split screen - mode 43 or 50 lines                */
  677. /*--------------------------------------------------------------------------*/
  678. void split_screen()
  679. {
  680.   union REGS r;
  681.  
  682.   r.x.ax=0x1112;
  683.   r.h.bl=0;
  684.   int86(0x10,&r,&r);
  685. }
  686. /*--------------------------------------------------------------------------*/
  687. /*                           Set the video mode                             */
  688. /*--------------------------------------------------------------------------*/
  689. void textmode(int mode_code)
  690. {
  691.   union REGS r;
  692.  
  693.   r.h.ah=0;
  694.   r.h.al=mode_code;
  695.   int86(0x10, &r, &r);
  696. }
  697. /*--------------------------------------------------------------------------*/
  698. /*          From 'C - The Complete Reference', by Herbert Schildt           */
  699. /*--------------------------------------------------------------------------*/
  700. void goto_xy(int x,int y)
  701. {
  702.   union REGS r;
  703.  
  704.   r.h.ah=2;
  705.   r.h.dl=x-1;                               /* Subtract one to allow Turbo C*/
  706.   r.h.dh=y-1;                               /* addressing.  The Turbo C 1.5 */
  707.   r.h.bh=0;                                 /* gotoxy routine apparently    */
  708.   int86(0x10, &r, &r);                      /* doesn't allow 43 or 50 lines */
  709. }
  710. /*--------------------------------------------------------------------------*/
  711. /*                            Read the scan code                            */
  712. /*--------------------------------------------------------------------------*/
  713. int inkey(int *scan)
  714. {
  715.   union REGS r;
  716.  
  717.   r.h.ah=0;
  718.   int86(0x16, &r, &r);
  719.   if(!r.h.al) {
  720.     *scan=r.h.ah;
  721.     return(0);
  722.   }
  723.   else {
  724.     *scan=r.h.al;
  725.     return(1);
  726.   }
  727. }
  728. /*--------------------------------------------------------------------------*/
  729. /*                         Get the video card type                          */
  730. /*--------------------------------------------------------------------------*/
  731. int video_card(int *max_col,int *max_row)
  732. {
  733.   union REGS r;
  734.  
  735.   textmode(0);
  736.   textmode(3);
  737.   textmode(16);
  738.   textmode(18);
  739.  
  740.   r.h.ah=15;                                /* Get the mode set             */
  741.   r.h.al=50;
  742.   int86(0x10, &r, &r);
  743.  
  744.   *max_col=r.h.ah;                          /* This is number of columns    */
  745.  
  746.   if(r.h.al>18) *max_row=46;               /* VGA                          */
  747.   else if(r.h.al>=16) *max_row=40;         /* EGA                          */
  748.   else *max_row=22;                        /* CGA  -code by JLW            */
  749.  
  750.  
  751.   return(r.h.al);                           /* Return the mode              */
  752. }
  753. /*--------------------------------------------------------------------------*/
  754. /*                           Get the maze option                            */
  755. /*--------------------------------------------------------------------------*/
  756. void get_option(void)
  757. {
  758.   int divisor;
  759.   int keycode,scan;                         /* Used for when reading a key  */
  760.   static int maze_size;                     /* Flag to indicated maze size  */
  761.  
  762.   if(startup==1) {
  763.     goto_xy((max_col-28)/2,(max_row-7)/2);
  764.     printf("                            ");
  765.     goto_xy((max_col-28)/2,(max_row-7)/2+1);
  766.     printf("  1 - Variable small mazes  ");
  767.     goto_xy((max_col-28)/2,(max_row-7)/2+2);
  768.     printf("  2 - Full screen maze      ");
  769.     goto_xy((max_col-28)/2,(max_row-7)/2+3);
  770.     printf("  3 - Variable large mazes  ");
  771.     goto_xy((max_col-28)/2,(max_row-7)/2+4);
  772.     printf("  4 - User specified mazes  ");
  773.     goto_xy((max_col-28)/2,(max_row-7)/2+5);
  774.     printf("  5 - Exit to DOS           ");
  775.     goto_xy((max_col-28)/2,(max_row-7)/2+6);
  776.     printf("                            ");
  777.     do {                                    /* Get the maze size code       */
  778.       keycode=inkey(&scan);
  779.     } while(keycode==0||scan<49||scan>53);  /* Don't use bad keys           */
  780.     maze_size=scan-48;                      /* Make it 1 to 4               */
  781.   }
  782.   switch(maze_size) {
  783.     case 1:                                 /* Variable small maze          */
  784.       nrow=rand()/2000+5;
  785.       ncol=rand()/1200+8;
  786.       break;
  787.     case 2:                                 /* Full maze                    */
  788.       if (VGA) nrow=21;                     /* if logic added   by JLW  VGA */
  789.       else if (EGA) nrow=19;                /*          added   by JLW  EGA */
  790.       else nrow=10;                         /*          added   by JLW  CGA */
  791.       ncol=38;
  792.       break;
  793.     case 3:                                 /* Variable large               */
  794.       divisor=rand()/16383+1;               /* Weight to get more small ones*/
  795.       nrow=rand()/512/divisor+10;
  796.       ncol=rand()/256/divisor+10;
  797.       break;
  798.     case 4:                                 /* Size is read from user       */
  799.       goto_xy(1,2);
  800.       printf("Enter maze size (rows cols): "); /* remove comma JLW          */
  801.       scanf("%d %d",&num_row,&num_col);
  802.       nrow=(num_row-3)/2;                   /* Edit the # of rows           */
  803.       if(nrow<5)nrow=5;
  804.       ncol=(num_col-3)/2;                   /* Edit the # of cols           */
  805.       if(ncol<5)ncol=5;
  806.       break;
  807.     default:                                /* Exit                         */
  808.       textmode(3);
  809.       exit(0);
  810.   }
  811. }
  812.